上一篇原本希望完整介紹我的想法,但因平台篇幅限制,文章在後半段便中斷了。與其重新
改寫,我認為更重要的是先把原本的內容完整交代,因此有了這篇補充。
完整內容亦可於 CTT2BM(https://cscall.sourceforge.io/ctt2bm/) 閱讀
此文証明,所有文字與形式化知識,都可以在一致的程序架構下操作與驗證。也就是說,程
序語言不只是用來撰寫程式,也可以作為數學、演算法、邏輯以及其他可操作知識的共同語
言(事實上是超越目前的形式邏輯),如同組合語言或 C/C++ 能以明確的操作步驟描述問題>一樣。
以下便是上一篇被截斷的後半段內容。
定理3: ℝ,ℕ集合間無法1-1對應.
証: ℝ,ℕ集合間若可1-1對應,則無限與有限的運算操作會等價,無限長的小數(如各種無理
數)會是多餘的,不合事實. 另參考對角論證法(Cantor's diagonal argument):
1.假設自然數與實數1-1對應,並想像成一張完成的列表.
2.由此列表中總可找出一斜角元素使得以上假設不成立.
註: Cantor理論很多地方都是有問題的. "線段中有多少點"或"實數集中有多少元素"的
問題等價"1/0"的求值問題,目前没有合理解.
若說一條實數線上(或集合)有x個點,那麼它總會遇到 1/x(點的長度,或是點與點間
距離的問題. 既然點的長度為零(公理),它就必須面對 1/0 的問題(而1/0 是未定義
的).
命題9: 實數無法每個全都能明確定義.
証: 因實數可以是無限長的離散符號, 而定義文字本身有限. 另由以上定理也可証.
例: 若無特別定義, "0.999..." 是個不定數,不易明確定義 (註: "小數全都9"這種敍述
無法明確定義一數. 這點可想像當數以1-進制表達時狀況). 或者:
"比1小無限小的數"也是種(非加法)觀點的0.999...
A= lim(n->∞) 1-3/10^n = lim 0.999... =1
B= lim(n->∞) 1-2/2^n = lim 0.999... =1
C= lim(n->∞) 1-1/n = lim 0.999... =1
具有結構的0.999... (可由無限級數理解,因承載可辨識資訊)
D= 0.99(99(9))(9)
若以此例解釋以上命題3中的0.999...代數魔術, 可說100.999... 連續乘10只能於
有限步驟內看到前面的9,而看不到尾段真正的數結構. 並且100.999... 的處理方式
會改變數結構.
這點對於無限級數很重要, 因無限級數所定義的數可能因此已改變. 此例並說明,在
極限 lim(x->c) f(x)= L 的表述中, f(c)=L 的推導是錯誤的. 因極限的定義已再三
強調f於c的值是未定義的. "0.999...的極限是1" 與"0.999...=1" 是全然不同兩碼
事.
註: 數字可視為文字的子集, 文字也可視為數字的子集. 此命題也是說實數無法完全每個
都能用文字定義.
極限::= lim(x->a) f(x)=L
極限的精髓在於提供一種不藉由等式來定義描述數的方法(即,直接'猜測'L後由某方式,
如ε-δ敘述確認性質). 極限意思是說: x趨近c (x≠c)時,f(x)的極限是L(滿足ε-δ敘述),
不是"當x趨近於c, 最後f(c)等於L".
譬如1: A= lim(n->∞) 1-1/n= lim(n->0⁺) 1-n= lim 0.999...=1
B= lim(n->∞) 1+1/n= lim(n->0⁺) 1+n= lim 1.000...=1
譬如2: A=lim(x->ℵ₀) f(x), B=lim(x->ℵ₁) f(x) // ℵ₀,ℵ₁是否恰當是另個問題,但若
// 採“最終將相同”解釋,會有問題:
// f(ℵ₀)與f(ℵ₁)是否相等?
註:極限是定義在已存的數系上,極限無法用來定義其所使用的(趨近序列)數. 這種類型
的推論稱爲"循環論証". 許多有闗實數的理論都有循環論証的疑慮.
註:極限的乘法公式(lim(x->c) (f(x)g(x))= (lim(x->c) f(x))(lim(x->c) g(x)) )
可能有點問題:
設A=lim(n->∞) (1-1/n)= 1
AA..*A= ... = lim(n->∞) (1-1/n)^n // 1=1/e ?
極限運算不是一個決定性過程. 有關e的問題還很多,目前只能到此為止.
註:'無限小'事實上可能並不小,因每個'可列出'的趨近序列所表區間[x,c),大致來說
仍與[0,1]區間保持1-1對應關係.
註:冪函數的差商(微分)問題可能可以建立等式關係.
無限級數::= 含無限多加項的級數, 如: Σ(n=0,∞) a(n)= a(0)+ a(1)+ a(2) +... +a(∞)
一般而言,無限級數的加總運算無法於有限步驟內完成. 這是'無限∞'的語意.
無限級數的程序表法:
Int n=0;
RealNumber sum=0;
for(n=0;;++n) { // n無上限
sum+= f(n);
}
return sum; // unreachable (程序本身無法回答sum的確定值)
一般來說此程序不終止,Σ(n->∞) f(n)=L 表法中的等號有問題,因為程序無法給出某定值
的sum. 無額外資訊情況下,最多只能找理由推斷sum 無限趨近L(若L已知). 或直接定義
L= Σ(n->∞) f(n).
無限級數運算原則: 展開式中索引爲∞的加項(通常是最後一項) 必須列出,以表示加項結構
或表示'餘量'. 並且,展開式的算法與一般非無限級數算法相同:
例1: 設S= Σ(n=0,∞) a^n = 1+a+a^2+...+a^∞
S= 1+a*(1+a+a^2+...+a^∞)-aa^∞
<=> S= 1+aS-a^(∞+1)
<=> S(1-a)=1-a^(∞+1)
<=> S= (1-a^(∞+1))/(1-a)
例2: 設S= Σ(n=1,∞) n = 1+2+3+...+∞
S= 1+2+3+...+∞ // (1)
S= ∞+...+3+2+1 // (2)
2S= ∞*(∞+1) // (1)+(2)
<=> S= ∞*(∞+1)/2
不列尾項時,展開式會有重排的'魔術算法'問題, 因展開式重排結果會改變原級數
的定義:
闢如1: S可經由重排而成(幾乎)任意數:
S= Σ(n=1,∞) n= 1+2+3+... =1+1+1+1+...= (1+1)+(1+1+1)+...
= Σ(n=1,∞) n+1 // S定義被改變
// (或者 S=(1+2)+(3+4)+... = Σ(n=1,∞) 4*n-1)
闢如2:
S=1+2+4+8+... // 忽略尾項(病式)
<=> S=1+2*(1+2+4+8+...) // 多種可能的重排法
<=> S=1+2S
<=> S=-1
明示尾項可避開魔術算法問題:
S=1+2+4+8+...+2^∞
<=> S=1+2(1+2+4+...+2^(∞-1))
<=> S=1+2S-2^(∞+1)
<=> S=2^(∞+1)-1 // 這類忽略尾項得到S=-1的魔術算法例子在youtube上相當
// 多(含∞的加項被删/略掉)
以下的四個無限級數運算規則可由上列的無限級數運算原則導出. 証明很直接,所以未列出.
基本上,有限級數的公式亦適用於無限級數 (但,數學歸納法不適用於無限級數公式的證明,
因爲∞的義意是'程序不終止',而於推理時,Peano公理'程序'的應用次數必須有限).
定理1: 設s1,s2爲兩無限級數. s1=s2 <=> s1-s2=0 // 無限級數等於的判別定理
定理2: Σ(n=0,∞) a(n)= a(0)+ Σ(n=1,∞) a(n) // 移項規則
= a(∞)+ Σ(n=0,∞-1) a(n)
定理3: Σ(n=0,∞) f(n) ± Σ(n=0,∞) g(n) = Σ(n=0,∞) f(n)±g(n) // 加法規則
定理4: Σ(n=0,∞) cf(n)= c(Σ(n=0,∞) f(n)) // 常數積規則
註: 許多(特別有關π,e)無限級數‘等式’可由以上定理証明不成立. 這類式子實際上
應稱爲近似式(極限f(c)=L的盲點).
如: Σ(n=1,∞) 1/n² ≒ π²/6
Σ(n=0,∞) (-1^n)*(1/(2n+1)) ≒ π/4
Σ(n=0,∞) k^n/n! ≒ e^k
因此, 收㪘(有極限)的無限級數應該加用"lim"或使用'≒'(除定義外)寫成,譬如:
lim(k->∞) Σ(n=0,k) (-1^n)(1/(2n+1)) = π/4 或者
Σ(n=0,∞) (-1^n)(1/(2n+1))≒ π/4
如此這様,數式的義意比較凖確點,較不易犯錯.
悖論: 這個例子應有助於解釋無限大∞的概念:
設數列 A(0)=0
A(n)= (A(n-1)+1)/2, n∈{0,1,2,3,...}.
問: n爲何數才能使得A(n)= 1?
答: 由於1/2+1/4+1/8...= 0.999...(也是一種0.999...) 無法等於1. 因此沒有正整
數n(含無限大)能使得A(n)=1,也就是說, n值不在給予的題意中. 此答案亦適
用基本的Zeno 悖論,超級任務,..等悖論. 通常這類悖論會另給速度,時間資訊
(兩個模型) 而強問"時間到時, n值爲多少?".
實數是人對於類比量的描述,有大小,能運算,..都有具體的實用性質... 簡單說,實數就是
小學生也懂的小數(可無限長). 除較深義意的'無限'部份外,實數本身沒有特別地方.
實數的算盤定義:
ℝ::= {x| 設A(n)表示一有小數點及長度不限的算盤, n表進制. x為A(n)所表達的數
其中n∈ℕ,n>=2 } // 反過來說,每個實數就是個算盤數.
實數若完全形式化表述,則其'理論'或許可如下定義(終究爲理論建構問題,目前不是很
重要):
n-進制定㸃數::= 由n-進制數字串所表達的數. 此字串可含一個負號及小數點:
<fixed_point_number>::= [-] <wnum> [ . <frac> ] // 除"-0"外
<wnum>::= 0
::= <nzd> { 0 | <nzd> }
<frac>::= { 0 | <nzd> } <nzd>
<nzd> ::= 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 // '數字'會隨進制改變
譬如: 78, -12.345, 3.1414159...
設ℝ爲n-進制定㸃數所表數的集合, 則ℝ= ℝ<2> ∪ ℝ<3> ∪ ℝ<4> ∪ ... ∪ R<∞>
n-進制定㸃數定義法與公理1相容,中間很多技術細節,但目前已充份.
n-進制定㸃數的加減算法同小學教的(或算盤上的)算法. 任兩相同n-進制的進制數
a,b 所表的數相同 唯若且若 a,b的 <fixed_point_number>表達完全相同(或a-b=0).
若a≠b, 則a>b 或 a<b, 擇一成立 (三一律).
註: 實數也可如此定義,非常直覺簡單:
EN(擴充自然數)::= 同Peano所定義的自然數,但數字(符號元素)可無限長.
ℝ::= {x| x=p/q 或-p/q, p,q∈EN, q≠0}
若某公式能証明於有理數成立,則這種定義可能易証其於實數也成立.
註: 實數是為處理實際工程/物理問題而'發明'存在. 由'純理論'定義開始的'實數'理論
行不通, 因為所有推論(若應用於實際事物,如計數,..)都無效.
証明(同計算)一般來說是種由問題敍述到結論的有限推導步驟. '計算'通常指推導過程
遵循某標準規範,而'証明'難有標準規範,這就有了很大的可能性空間.
理論服務事實,事實本身才是真正的無字公理. 小明有1隻雞,又買了2隻雞. 搬手指數數1,
2,3隻指頭就是3隻雞的証明, 與算式/理論(証明也是種計算/操作)1+2=3是兩回事.
'美麗嚴格'的數理証明要求對於'太'基本的東西是無效的(顛倒因果).
另方面,目前的數學/邏輯對於無限仍無足夠共識可建構'嚴格'証明. 這是以上"平凡"証明
的解釋. 其實很多東西是先驗(心)決定的,我們先決定所真想要的是什麼,再找証明,包含
所謂客觀(但我們可改善品質).
註: 現實是我們離散認知的產物,至少在透過形式系統/語言(formal system/language)
進行嚴格表達時是如此. 以下為支持這種觀點的一個証據:
點間距離公設::= 任兩點P,Q間有距離度量, 2維點dist函數的基本性質(累加性與
比例性)
dist(A,B)=dist(B,A)
dist(<x,y>,<0,0>)=dist(<|x|,|y|>,<0,0>)
直線(2D)::= 設<a,b>爲非原點, 則L(<a,b>)={<x,y>| ∀u∈ℝ, <x,y>=u*<a,b>} 爲
過原點直線集合.
證: <0,0>∈L (u=0), P=<a,b>∈L (u=1), 可證 ∀p∈L, dist度量滿足(先前的)直線
定義.
經由點群平移可得直線(2維數)的ㄧ般定義:
設A=<x1,y1>, B=<x2,y2>), A≠B, 則線集合L(A,B)≡{p| dy=y2-y1, dx=x2-x1,
∀t∈ℝ, p=<x1+tdx, y1+tdy> } (或L(A,B)= {p| ∀t∈ℝ, p= A+t*(B-A)})
勾股弦定理(畢氏定理)::= 對任兩點A=<Ax,Ay>,B=<Bx,By>. 設C=<Bx,Ay>, 直線
L(A,B)中存在ㄧD點,0<u<1, D= A+u*<Bx-Ax, By-Ay> 使得 △ACB ∼ △ACD ∼ △CDB
證: 此命題的2維數(向量)證法冗長(略)
設c=dist(A,B), c1=dist(A,D), c2=dist(D,B), a=dist(A,C), b=dist(B,C).
由相似形邊長比相等(證略)得 (1) a/c=c1/a <=> aa= cc1, (2) b/c=c2/b
<=> bb= cc2 (1)+(2) <=> aa+bb= c*(c1+c2)= c*c
∴ 由距離公設可得dist(A,B)的完整定義: dist(A,B)^2= (Bx-Ax)^2 + (By-Ay)^2
在二維數的觀點下,只要滿足距離公設即可構成歐氏幾何系統.
此証可視為一種"數學=物理"的觀點: 也就是說,透過物理實驗來尋找數學真理是
有效的. 反過來說,如果我們無法讓某個數學想法在現實中客觀重現,那麼那個
數學想法是有問題的.
名稱 (NAME)
BitMachine - 用於位元字串(bit-string)與標籤(label)映射的類別
概要 (SYNOPSIS)
除了 POD 型別與 C 結構之外,所有型別皆宣告於 Wy 命名空間(namespace)中 。
#include <CSCall/BitMachine.h>
BitMachine 類別是由二元節點(binary nodes)組成的圖形結構。每個節點包含兩個分支 。
BitMachine 類別扮演著雙重角色 :
公有成員 (PUBLIC MEMBERS)
typedef signed short LabelType
typedef unsigned char CharType
typedef size_t IdxType
static constexpr IdxType NoIdx
class Reply
class Node
class Branch
BitMachine()
BitMachine(const BitMachine&)
BitMachine(BitMachine&,ByMove_t)
explicit BitMachine(unsigned int)
bool is_default() const
unsigned int symbits() const
size_t num_nodes() const
size_t num_labels() const
IdxType root_index() const
LabelType get_lab(const void*, size_t) const
static LabelType default_ocb(LabelType, LabelType)
static LabelType lesser_ocb(LabelType, LabelType)
static LabelType greater_ocb(LabelType, LabelType)
Errno add_case(const void*, size_t, LabelType,
LabelType(&)(LabelType, LabelType)=default_ocb)
Errno run(void*, size_t, HaltStat&) const
const Node& _node(IdxType) const
Node& _node(IdxType)
IdxType _alloc_node_space()
IdxType _alloc_node(Branch, Branch)
void _remove_node(IdxType)
void _set_root_index(IdxType)
void swap(BitMachine&)
void reset()
Errno reset(const BitMachine&)
Errno reset(unsigned int)
BitMachine& operator=(const BitMachine&)
輔助函數 (AUXILIARY FUNCTIONS)
Errno merge_duplicate(BitMachine&)
Errno shrink(BitMachine&)
size_t s4tape(const char*, void*)
String wrd(const BitMachine&)
String wrd(const BitMachine::HaltStat&)
成員說明 (DESCRIPTION)
class Node
詳見 Wy.BitMachine.Node.3wy 手冊 。
class Branch
詳見 Wy.BitMachine.Branch.3wy 手冊 。
BitMachine()
建構預設物件 。
symbits() = 1
num_nodes() = 0
num_labels() = 0
root_index() = NoIdx
BitMachine(const BitMachine& s)
由物件 s 進行複製建構。
symbits() = s.symbits()
num_nodes() = s.num_nodes()
num_labels() = s.num_labels()
root_index() = s.root_index()
[拋出異常] Reply
ENOMEM 記憶體不足
BitMachine(BitMachine& src, ByMove_t)
將 src 物件轉移(Move)至 this 指向的記憶體位址 。
explicit BitMachine(unsigned int sbits)
建構一個使每個磁帶符號佔用 sbits 位元的位元機物件 。
symbits() = sbits
num_nodes() = 0
num_labels() = 0
root_index() = NoIdx
[拋出異常] Reply
EINVAL sbits 為零
bool is_default() const
確認 *this 是否等價於預設物件 。
[返回值] true: 物件等價於 BitMachine()
false: 其他情況
unsigned int symbits() const
取得每個磁帶符號的位元數 。
[返回值] 每個符號佔用的位元數量 。
size_t num_nodes() const
取得 *this 中包含的節點數量 。
注意:在圖靈機的視角中,節點(node)對應於機器的狀態(state) 。
[返回值] *this 中的節點數量 。
size_t num_labels() const
取得 *this 中帶有標籤的節點數量 。
[返回值] *this 中帶有標籤的節點數量 。
IdxType root_index() const
取得 *this 中根節點(root node)的索引值 。
[返回值] 根節點的索引。若 *this 為預設狀態,則返回 NoIdx。
LabelType get_lab(const void* data, size_t nbits) const
取得由 [data, nbits] 所指向的位元字串關聯的標籤值 。
位元字串從第一個字元開始被解析為無符號字元(unsigned char)陣列,每個字元皆自
LSB(最低有效位元)處理至 MSB(最高有效位元) 。
此成員函式假設 *this 的每個分支皆不修改磁帶,且讀寫頭(r/w head)一律向右移動
(標籤分支除外) 。
[返回值] >= 0: 該位元字串 [data, nbits] 的標籤值
< 0: 找不到該位元字串
static LabelType default_ocb(LabelType oldv, LabelType newv)
static LabelType lesser_ocb(LabelType oldv, LabelType newv)
static LabelType greater_ocb(LabelType oldv, LabelType newv)
default_ocb 是 add_case 的預設回呼函數(callback function),供應用程式決定當
發生標籤覆寫(overwritting)時應設定何值 。
oldv 為原始標籤值,newv 為新傳入的值 。
預設回呼函數一律返回 oldv(即永遠不變動舊值) 。
lesser_ocb 返回 oldv 與 newv 之間的較小值 。
greater_ocb 返回 oldv 與 newv 之間的較大值 。
[返回值] 用於覆寫的標籤值 。
Errno add_case(const void* data, size_t nbits, LabelType lab, LabelType(&ocb)(LabelType, LabelType)=default_ocb)
將位元字串 [data, nbits] 與標籤 lab(範圍在 [0, SHRT_MAX] 內的數值)的關聯加入
*this 中 。
若該位元字串與標籤的關聯已實存,則回呼函數 ocb 會被呼叫,並傳入原始標籤值與新
標籤值 lab 。ocb 返回的值將被註冊為新的標籤值 。
若該關聯不存在,則會建立一個嶄新的關聯 。
在圖靈機的視角中,每個分支皆被設定為「將讀回的相同位元寫回磁帶」,且讀寫頭一律
向右移動(標籤分支除外) 。若與既有路徑發生衝突,此成員將返回 EMLINK
。若發生錯誤,*this 可能會處於不一致的狀態 。
[返回值] Ok: 成功
EFAULT: data 為 NULL
EINVAL: lab < 0 或 nbits 無法被 symbits() 整除
EMLINK: 無法對已實存的路徑加上標籤
EEXIST: data 的前綴(Prefix)已被加上標籤
ENOMEM: 記憶體不足
Errno run(void* tape, size_t nbits, HaltStat& stat) const
將 *this 作為圖靈機(Turing Machine)運行 。
[tape, nbits] 指向包含初始資料與工作空間(working space)的可讀寫磁帶 。
此成員函式模擬了上述 get_lab(..) 成員的行為 。
struct HaltStat { // 停機狀態結構體
enum StopCond {ExcBegin, // 讀寫頭超出 *tape 的第一個位元
ExcLast, // 讀寫頭超出 *tape 的最後一個位元
Label, // 遭遇標籤節點
NoRule}; // 無可用規則繼續執行(無規則停機)
StopCond stop_cond; // 停機條件
LabelType label; // 遭遇到的標籤值
BitPtr head; // 磁帶的讀寫頭指標(r/w head pointer)
IdxType node_index; // 最後執行的節點索引(node index)
uint64_t steps; // 已執行的狀態轉移規則數量(步數)
};
[返回值] Ok: 成功。stat 將會被設定為停機時的狀態。
EFAULT: data(此處指磁帶指標)為 NULL
EINVAL: nbits 無法被 symbits() 整除
ENOENT: nbits == 0
EBADF: *this 為預設狀態或處於損壞狀態
const Node& _node(IdxType nidx) const
Node& _node(IdxType nidx)
取得索引值為 nidx 的節點引用(Reference)。
注意:此為底層核心成員。請務必確保 nidx 指向一個有效的節點,且 *this 處於
一致狀態 。
[拋出異常] Reply
EINVAL 無效的 nidx
[返回值] 位於索引 nidx 處的節點引用 。
IdxType _alloc_node_space()
配置一個節點空間 。該空間尚未被初始化(幕須使用 placement new
來初始化 Node 物件) 。
注意:此為底層核心成員。請務必確保返回的索引指向一個有效的節點空間,且 *this
處於一致狀態 。
[返回值] 節點空間的索引。若配置失敗則返回 NoIdx 。
IdxType _alloc_node(Branch lf, Branch rt)
配置一個左分支為 lf、右分支為 rt 的節點 。
注意:此為底層核心成員。請務必確保 *this 處於一置狀態 。
[返回值] 已配置節點的索引。若配置失敗則返回 NoIdx 。
void _remove_node(IdxType nidx)
移除位於索引 nidx 處的節節點 。
注意:此為底層核心成員。請務必確保根節點索引(root index)依然有效。
void _set_root_index(IdxType nidx)
將根節點索引設定為 nidx 。
注意:此為底層核心成員。請務必確保 nidx 指向一個有效的節點,且 *this 處於
一致狀態 。
void swap(BitMachine& ano)
將 *this 的狀態與另一個位元機物件 ano 進行交換 。
void reset()
Errno reset(const BitMachine& s)
Errno reset(unsigned int sbits)
將 *this 重新構造回對應引數之建構子所產生的狀態。
[返回值] Ok: 成功
ENOMEM: 記憶體不足
EINVAL: sbits 為零
BitMachine& operator =(const BitMachine& rhs)
將 *this 重新構造為與 BitMachine(rhs) 相同的狀態 。
[拋出異常] Reply
ENOMEM 記憶體不足
[返回值] *this 的引用 。
輔助函數說明 (AUXILIARY FUNCTIONS DESCRIPTION)
Errno merge_duplicate(BitMachine& bm)
合併位元機 bm 中重複的子樹(sub-trees)結構。
[返回值] Ok: 成功
ENOMEM: 記憶體不足
Errno shrink(BitMachine& bm)
透過重新配置節點,收縮並最佳化 bm 記憶體圖形結構中的記憶體消耗量。
通常此成員函數會在呼叫 merge_duplicate(..) 之後被調用 。
[返回值] Ok: 成功
ENOMEM: 記憶體不足
size_t s4tape(const char* s4str, void* tape)
將以零結尾的 4 字母磁帶字串 s4str(包含 '0'、'1'、'2'、'B')轉換為位元機
的 2 字母(二進位二位元)磁帶字串,並儲存至 tape 所指向的陣列中。
四個字母 '0'、'1'、'2'、'B' 分別被依序轉換為兩個位元的 00、01、10 和 11 。
[拋出異常] BitMachine::Reply
EFAULT tape 為 NULL
EINVAL s4str 為 NULL
EBADMSG tape 中包含無效字元
[返回值] 寫入 tape 的位元數量(即 2 * strlen(s4str)) 。
String wrd(const BitMachine& bm)
取得該位元機(BitMachine)物件的字串表達形式 。
[拋出異常] String::Reply
ENOMEM 記憶體不足
[返回值] 包含位元機字串表達形式的 String 物件 。
String wrd(const BitMachine::HaltStat& hs)
取得該停機狀態(HaltStat)物件的字串表達形式 。
[拋出異常] String::Reply
ENOMEM 記憶體不足
[返回值] 包含 HaltStat 字串表達形式的 String 物件 。
參見 (SEE ALSO)
Wy.BitMachine.Node
Wy.BitMachine.Branch
Wy.BitPtr
Wy.Sct.Spu
Wy.Subset
備註 (NOTE)
專案目前正處於積極開發階段 。網址:https://sourceforge.net/projects/cscall
名稱 (NAME)
Spu - 通用型 CPU(Soft-CPU)類別
概要 (SYNOPSIS)
除了 POD 型別與 C 結構之外,所有型別皆宣告於 Wy 命名空間(namespace)中。
#include <CSCall/SctBase.h>
Spu 是圖靈機(Turing Machine)的物件導向模型(類別),其運作方式類似於
基於通用型 CPU 的計算機,用以提供計算語言(用於程式設計或程式間通訊)的
語義。其應用兼具理論與實用價值。
Spu 與通用型 CPU(或圖靈機)的主要區別在於,Spu 沒有「暫存器(register)」
或「旗標(flag)」(這些功能可以透過其他方式模擬),Spu 僅包含一個帶子
(tape)與一個堆疊(stack)。帶子在初始狀態下是空的。
帶子中的每個物件(稱為帶子變數或儲存格 cell)皆透過 Alloc 指令進行配置,
並由連續的索引編號來識別。帶子變數可以是任何 C++ 型別,包括 Spu 本身。
Spu 的指令由應用程式自行定義,因為不同用途的指令差異極大。除了少數
必要指令外,為了日常使用的便利性,系統定義了約 30 多個常用指令,詳見
manpage Wy.Sct(3wy)。
為了清晰起見,以下文件在提及 Spu 時皆省略了作用域名稱 Wy::Sct。
公開成員 (PUBLIC MEMBERS)
class Reply
typedef ssize_t
IndexType Spu()
~Spu()
InstrIdx next_instr
Array<InstrIdx> istack
Array<unsign char> tape
PtrArray<InstrBase> program
template<T> const T& get_data(IndexType) const
template<T> T& get_data(IndexType)
const std::type_info& get_typeinfo(IndexType) const
void set_instr_base(Spu&)
Errno run(InstrIdx)
Errno step()
void add_instr(InstrBase*)
輔助函式 (AUXILIARY FUNCTIONS)
SPU_INSTR_LAB(spu,lab)
Errno fix_label(Spu&)
constexpr InstrIdx Label(void*)
描述 (DESCRIPTION)
class Reply
繼承自 Errno 的類別專屬異常拋出型別(throw type)
Spu()
建構預設物件
next_instr= 0
istack = Default (預設)
tape = Default (預設)
program = Default (預設)
InstrIdx next_instr
即將執行的指令索引(即 program 陣列的索引)
Array<InstrIdx> istack
指令索引的堆疊
Array<unsign char> tape
儲存帶子變數(tape variables)的陣列。
所有帶子變數皆透過 Alloc 指令進行配置。第一個配置的帶子變數被分配
索引編號 0,第二個為 1,依此類推。帶子變數的索引編號可以為負數。
-1 代表最後一個配置的物件,-2 代表倒數第二個物件,依此類推。
帶子變數是透過成員函式 get_data(..) 進行存取。
PtrArray<InstrBase> program
包含指令的陣列。陣列中的每個指令皆與一個指令索引編號相關聯。
template<typename T> const T& get_data(IndexType vidx) const
template<typename T> T& get_data(IndexType vidx)
獲取儲存在變數索引 vidx 處、型別為 T 的資料參照(reference)。
如果 T 不是 VarPtr 型別,且 vidx 指向一個 VarPtr 型別的物件,
則該 VarPtr 的內容將被用作實際的變數索引編號。
注意:回傳的參照可能會因帶子重新配置(通常由 Alloc 指令引起)而失效。
[拋出異常] Reply
ErrVarIdx 變數索引超出範圍
ErrDataType 型別不符
ErrTapeIdx 低階帶子索引錯誤
[回傳值] 儲存在變數索引 vidx 處、型別為 T 的資料參照
const std::type_info& get_typeinfo(IndexType oidx) const
[拋出異常] Reply
ErrVarIdx 變數索引超出範圍
[回傳值] 儲存在變數索引 vidx 處資料的 std::type_info 參照
void set_instr_base(Spu& spu)
將 program 中的所有指令設定為參照至 spu
Errno run(InstrIdx beg_idx)
從索引 beg_idx 開始執行程式
程式會持續執行,直到 Fin 指令被執行為止。
若拋出衍生自 Errno 的物件,將會被捕捉並以 Errno 形式回傳。
[回傳值]
ErrInstrIdx 無效的 beg_idx 或來自程式的指令索引錯誤
ErrVarIdx 變數索引超出範圍
ErrDataType 型別不符
ErrTapeIdx 低階帶子索引錯誤
...
Errno step()
執行 next_instr 所指向的下一個指令並回傳
[回傳值] Ok 成功
ErrInstrIdx 程式索引超出範圍
ErrVarIdx 變數索引超出範圍
ErrDataType 型別不符
ErrTapeIdx 低階帶子索引錯誤
...
void add_instr(InstrBase* instr)
將 instr 附加(Append)至 program 尾端,並將該加入的指令
設定為參照至 *this
[拋出異常] Reply (或其他)
EFBIG 容量將超過最大限制
ENOMEM 記憶體不足以進行重新配置
...
輔助函式 (AUXILIARY FUNCTIONS) SPU_INSTR_LAB(spu, lab)
SPU_INSTR_LAB 是一個巨集(macro),用來註冊 Spu 物件 spu 的程式大小
以及與標籤(label)lab 的關係,藉此減輕在 C++ 中編輯 Spu 程式時
追蹤指令索引的麻煩。
SPU_INSTR_LAB 應該緊接在標籤宣告之後加入。
使用範例:
Spu spu;
spu.add_instr( new Alloc<char>() );
lab1:; SPU_INSTR_LAB(spu, &&lab1);
spu.add_instr( new Jmp(Label(&&lab1)) );
注意:此巨集為實驗性功能,旨在方便於 C++ 中編輯 Spu 程式。
Errno fix_label(Spu& spu)
修正使用 SPU_INSTR_LAB 巨集的 Spu 程式標籤。
Spu 程式的標籤只能被修正(fix)一次。
注意:此函式為實驗性功能,旨在方便於 C++ 中編輯 Spu 程式。
[回傳值] Ok 成功
ESRCH 找不到所參照的標籤
constexpr InstrIdx Label(void *addr)
將標籤值 addr 轉換為 InstrIdx 數值
注意:此函式為實驗性功能,旨在方便於 C++ 中編輯 Spu 程式。
[回傳值] InstrIdx 數值
參見 (SEE ALSO)
Wy.Sct(3wy) Wy.ArtNeuron Wy.BitMachine
備註 (NOTE)
除了本函式庫自行加入的錯誤回應外,其餘回應皆是由底層 C 函式庫函式回報的 errno 轉換而來。這些
回應的簡要說明源自 Linux 程式設計師手冊(Linux Programmer's Manual)。詳情請參閱相關的
manpage。
專案開發中。 https://sourceforge.net/projects/cscall
由以下的軟體生命概括流程, 各種現實改變可以case,rule方式表達:
(1)客戶user端:
提供用例: 1. by case 2. by rule
其它需求(Requirement)
(2)工廠workshop端:
建模, 建spec, 建程式
測試-> 循環 goto (1),(2)
(3)應用端: // 多數為原客戶端(1)
需求改變 -> 改變 (by case, by rule). 循環goto (1)
環境改變 -> 改變 (by case, by rule). 循環goto (1)
(假設每個磁帶符號有n bits,則最多有2^n個符號)
及下為示意的語法定義. ()表選一. []表選一或不選. {}表重複0次以上.
<bml> ::= {<node>}
<node>::= [<nid>]: [<hpos>] <branch> {; <branch>} [';;' <act>]
::= [<nid>]: ;; <act>
<branch>::= <match> <act> | <na>
<match>::= [!] <rsym> /
::= [!] '{' {<rsym>} '}' /
<act> ::= <wsym> <dir> [<nid>]
::= <wsym> <lab>
<dir> ::= (< >) // 讀寫頭移動方向(左或右)
<rsym>::= 能讀的tape符號
<wsym>::= 能寫的tape符號
<na> ::= 無規則終止
<lab> ::= 終端branch(或終端node)值
<nid> ::= node ID
<cmt> ::= "//" {<cmt_text>} // 註解
<hpos>::= 保留'較高階'語言使用(如,先移動讀寫頭至hpos位置...)
Ex: 讀寫頭移至X位置,寫Y
12: X/Y > [13] ;; - > <12> // 若所讀符號不是X,則不改寫所讀符號並持續右移
13: // next
對於一般程式, 因變數及函式數量固定, 每個變數及函式返迴位置都可設唯一相應的
tape符號,此法可易處理建構asm語言時遇上的定址問題.
以下例子假設tape的開始區域已配置一塊堆疊區的可能asm寫法.
Ex: Call // 呼叫函式func的asm可能寫法
10: H/<12> > 11 ;; - < 10 // 左尋堆疊頂符號H,代換為返迴位置12的符號<12>,
// 磁頭右移,轉移至 11
// (其它所讀符號寫回原值,跳至10,重複)
11: ;; H > // 更新堆疊頂符號H, 磁頭右移, 轉移至
12: ...
Ex: 函式func定義
func: ...
// 以下為'ret'的模擬
20: H/B < 21 ;; - < 20 // 左尋堆疊頂符號H,代換為空白符號B
21: <1>/H > 1 ; <2>/H > 2;
<3>/H > 3 ; ... ;; ... // 依符號跳至相應node,並'pop'堆疊
註: 藉由函數呼叫的例子顯示,基本計算機(圖靈機)理論問題可直接使用(符號)組合語言
作為分析工具(更高階C/C++亦可,但較難精準描述細節).
註: 可能解釋OOP效果的一個客觀解釋: 磁頭位置為指令中運算的context, 程式碼
敍述會簡潔緊湊.